/*
*@namespace
*@description This namespace contains objects used in the 'kaffipad' application
* for datahandling and communication against the Yast service
*@config Fractions of this library depends on the Google javascript library
*Angular.js and underscore.js to work
*
*/
var YStamp=YStamp || {}//Initializes the YStamp namespace if not existing

/**
 *@class KaffipadConsumption
 *@description An object holding the timestamp for a coffee consumption
 *@param timestamp should be the unix time in seconds
 */
YStamp.KaffipadConsumption = function KaffipadConsumption(timestamp, id){
    if(_.isUndefined(timestamp)){
        this.timestamp=Math.round(new Date().getTime()/1000);
        return;
    }
    if(!(_.isNumber(timestamp))){
        timestamp=parseInt(timestamp);
    }
    if(_.isNumber(timestamp)){
        var length = (timestamp ==0) ? 1 : 1+Math.floor(Math.log(timestamp)/Math.LN10);
        if(length==10){
            this.timestamp=timestamp;
            if(!_.isUndefined(id)){
                this.id=id;
            }
        }
        else{
            console.log("new YStamp.KaffipadConsumption: failed because 'timestamp'("+timestamp+") parameter only had "+length+" digets");
        }
        return;
    }
    else{
        console.log("new YStamp.KaffipadConsumption: failed because 'timestamp'("+timestamp+") parameter was not a number");
    }
};

YStamp.KaffipadConsumption.prototype.setEmail = function(userEmail) {
    this.email = userEmail;
}

YStamp.KaffipadConsumption.prototype.getEmail = function() {
    return this.email;
}

/**
 *@function
 *@description Method returning a Yast compatible record of the comsumption
 */
YStamp.KaffipadConsumption.prototype.toRecord=function(projectId){
    record={
        typeId:4,
        project:projectId,
        variables:[this.timestamp],
        flags:0
    }
    return record;
}

/**
 *@class 
 *@description An object holding information about a kaffipad user
 *@param YStamp.User object for KaffipadUser
 *@param Coffee consuption for existing Yast user
 */
YStamp.KaffipadUser=function KaffipadUser(user,settings,consumption){
    this.stampUser=user;
    if(_.isArray(consumption)){
        this.consumption=consumption;
    }
    else{
        //Initialized the array
        this.consumption=new Array();
        //If a consumption object was given it is added to the consumption list(loosy validation)
        if(!_.isUndefined(consumption)&&!_.isUndefined(consumption.timestamp)){
            this.consumption.push(consumption);
        }  
    }
    if(!_.isUndefined(settings)){
        this.settings={
           borderColor:'black',
           nameColor:'black',
           consumptionColor:'black',
           backgroundColor:'white'
        }
    }
}

/**
 *@function
 *@description Method returning the email identifying this user
 */
YStamp.KaffipadUser.prototype.getEmail = function() {
    return this.stampUser.values.email;
}

/**
 *@function
 *@description Method returning an ArrayList of unsynchronized consumption objects for the kaffipad user
 */
YStamp.KaffipadUser.prototype.getUnsynchedConsumption=function(){
    var unsyncedConsumption=new Array();
    for(var i=0;i<this.consumption.length;i++){
        if(_.isUndefined(this.consumption[i].id)){
            unsyncedConsumption.push(this.consumption[i]);
        }
    }
    return unsyncedConsumption;
}

YStamp.KaffipadUser.prototype.synchronizeCookieConsumptions = function(consumptions) {
    for (var i = 0; i < consumptions.length; i++) {
        if (consumptions[i].getEmail() == this.getEmail()) {
            var found = false;
            for (var j = 0; j < this.consumption.length; j++) {
                if (this.consumption[j].timestamp == consumptions[i].timestamp) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                this.consumption.push(consumptions[i]);
            }
        }
    }
}

YStamp.KaffipadUser.prototype.popUnsynchedConsumption=function(){
    var unsyncedConsumption=new Array();
    for(var i=0;i<this.consumption.length;i++){
        if(_.isUndefined(this.consumption[i].id)){
            unsyncedConsumption.push(this.consumption.splice(i,1)[0]);
            i--;
        }
    }
    return unsyncedConsumption;
}

YStamp.KaffipadUser.prototype.toString=function(){
    var stampUserToString=this.stampUser.toString();
    return "kaffipadUser["+stampUserToString+", with "+this.consumption.length+" consumptions]";
}

/**
 *@class
 *@description An object holding information about a YastStamp user
 *@param Email Email adress for existing Yast user
 *@param Password password for existing Yast user
 *@param Image avatar image for user prepresentation
 */
YStamp.User=function User(email, name, image){
    this.values={};
    if(_.isUndefined(email)){
        console.log("User(): Unvalid user initiated without email address");
    }
    this.values.email=email;
    this.values.name=name;
    this.values.image=(_.isUndefined(image))?"img/users/avatars/clooney.png":image;
    this.values.hash="";
    this.values.locked = true;
}

/**
 *@function
 *@description Checks if the user is logged in
 *TODO: Endre når det blir mulig å spørre Yast om brukere er logget inn eller ikke
 */
YStamp.User.prototype.loggedIn=function(){
    return this.values.hash.length>0;
}

/**
 *@function
 *@description Checks if the email/username has valid format
 */
YStamp.User.prototype.validateEmail=function(){
    var re = /\S+@\S+\.\S+/;
    return re.test(this.values.email);
};

YStamp.User.prototype.lock=function(){
    this.values.hash="";
    this.values.locked = true;
}
YStamp.User.prototype.unlock=function(hash){
    this.values.hash=hash;
    this.values.locked = false;
}
YStamp.User.prototype.isLocked = function() {
    return this.values.locked;
}
YStamp.User.prototype.toString = function(){
    var email=this.values.email;
    var locked=this.isLocked()?"Locked":"LoggedIn";
    return "user["+email+"[status:"+locked+"]]";
}


/**
 * @class
 * @param type a string representing the request type. All legal types are given
 * in RequestObject.values.validTypes
 * @param data contains all variables to be included in the request
 * @param succsess a function to handle request response
 * @param error a function to be handle request errors
 * @description A generalized object to handle JSON request against the Yast service
 */
YStamp.RequestObject= function(type,data,id){
    this.type="";
    if(!this.isValidType(type)){
        console.log("Ystamp.RequestObject.isValidType() failed at construct because "
            +type+" is not in Ystamp.RequestObject.values.validTypes");
    }
    if(_.isUndefined(data)){
    //        console.log("Ystamp.RequestObject failed at construct because data was 'undefined'")
    }
    this.data=data;
    
//    if(_.isUndefined(id)){
//        console.log("INFO: Ystamp.RequestObject initiated without 'id'");
//    }
//    this.id=id;
}

YStamp.RequestObject.prototype={
    values:{
        //URL to yast sever
        url:'http://www.yast.com/1.0/?lang=javascript&jsonp=JSON_CALLBACK&request=',
        //Valid request types
        validTypes:{
            login:"auth.login",
            getRecords:"data.getRecords",
            getProjects:"data.getProjects",
            getUserInfo:"user.getInfo",
            addData:"data.add"
        },
        //Generic status responses from Yast service
        yastResponseStatus:['success','unknown error','','access denied',
        'not logged in','login failure','invalid input','subscription required',
        'data format error','no request','invalid request','missing fields',
        'request too large','server maintenance']
    },
    //Checks if given request type is registerd as valid
    isValidType:function(type){
        if(_.contains(YStamp.RequestObject.prototype.values.validTypes,type)){
            this.type=type;
            return true;
        }
        else{
            return false;
        }
    },
    /**
     * @function
     * @description Carrying out the request against the Yast service.
     * @param $http is a core Angular service that facilitates communication 
     * with the remote HTTP servers via bthis.rowser's XMLHttpRequest object or via JSONP.
     * @return returns false if the request could not be done, se console log
     * for details
     */
    request:function($http){
        //Aborts function if $http is not given
        if(_.isUndefined($http)){
            return false;
        }
        if(this.validate()){
            //Deligate seccess on ajax request
            var loginJsonObject={
                req: this.type,
                id:this.id, 
                data:this.data
                };
            var JsonLoginString=JSON.stringify(loginJsonObject);
            var requestString=this.values.url.concat(JsonLoginString);
            //Executes the http request with json
            return $http.jsonp(requestString);
        }
        //Returns false if request is not valid
        else{
            return false;
        }
    },
    //This function could be refactored to validate object data as well
    //Mabye a validation object could be stored in the 'validTypes' array?
    validate:function(){
        return true;
    }
}
